From 58d5afee7b972380211cd6c1051616bd7a6fd1f7 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 14 Feb 2006 20:17:26 +0100 Subject: [PATCH] Clarify lazy FPU management in VMX domains. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/vmx/vmx.c | 22 ++++++++++++++++------ xen/include/asm-x86/hvm/vmx/vmx.h | 20 ++++++++++++++------ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 7348181fe9..1068ae0c66 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -617,12 +617,17 @@ static void vmx_do_no_device_fault(void) clts(); setup_fpu(current); + + /* Disable TS in guest CR0 unless the guest wants the exception too. */ __vmread_vcpu(v, CR0_READ_SHADOW, &cr0); - if (!(cr0 & X86_CR0_TS)) { + if ( !(cr0 & X86_CR0_TS) ) + { __vmread_vcpu(v, GUEST_CR0, &cr0); cr0 &= ~X86_CR0_TS; __vmwrite(GUEST_CR0, cr0); } + + /* Xen itself doesn't need another exception. */ __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM); } @@ -1152,14 +1157,17 @@ static int vmx_set_cr0(unsigned long value) */ __vmread_vcpu(v, CR0_READ_SHADOW, &old_cr0); paging_enabled = (old_cr0 & X86_CR0_PE) && (old_cr0 & X86_CR0_PG); - /* If OS don't use clts to clear TS bit...*/ - if((old_cr0 & X86_CR0_TS) && !(value & X86_CR0_TS)) + + /* + * Disable TS? Then we do so at the same time, and initialise FPU. + * This avoids needing another vmexit. + */ + if ( (old_cr0 & ~value & X86_CR0_TS) != 0 ) { - clts(); - setup_fpu(v); + clts(); + setup_fpu(v); } - __vmwrite(GUEST_CR0, value | X86_CR0_PE | X86_CR0_PG | X86_CR0_NE); __vmwrite(CR0_READ_SHADOW, value); @@ -1510,6 +1518,8 @@ static int vmx_cr_access(unsigned long exit_qualification, struct cpu_user_regs break; case TYPE_CLTS: TRACE_VMEXIT(1,TYPE_CLTS); + + /* We initialise the FPU now, to avoid needing another vmexit. */ clts(); setup_fpu(current); diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index 6d551edf8e..d0583a8290 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -382,14 +382,22 @@ static inline void vmx_stts(void) unsigned long cr0; struct vcpu *v = current; - __vmread_vcpu(v, GUEST_CR0, &cr0); - if (!(cr0 & X86_CR0_TS)) { + /* FPU state already dirty? Then no need to setup_fpu() lazily. */ + if ( test_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags) ) + return; + + /* + * If the guest does not have TS enabled then we must cause and handle an + * exception on first use of the FPU. If the guest *does* have TS enabled + * then this is not necessary: no FPU activity can occur until the guest + * clears CR0.TS, and we will initialise the FPU when that happens. + */ + __vmread_vcpu(v, CR0_READ_SHADOW, &cr0); + if ( !(cr0 & X86_CR0_TS) ) + { __vmwrite(GUEST_CR0, cr0 | X86_CR0_TS); + __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM); } - - __vmread_vcpu(v, CR0_READ_SHADOW, &cr0); - if (!(cr0 & X86_CR0_TS)) - __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM); } /* Works only for vcpu == current */ -- 2.30.2